iT邦幫忙

2023 iThome 鐵人賽

DAY 12
0
Mobile Development

[Android Studio & Spring boot 30天挑戰]系列 第 12

[Android Studio & Spring boot 30天挑戰] Day12- 摩斯密碼發送(下)

  • 分享至 

  • xImage
  •  

今天,我們迎來了這個簡單的專案的最後一天介紹。儘管這個特定的內容結束了,但我們的學習之旅還未結束。在過去的幾天裡,我們一步步地建立了一個功能強大且充滿創意的摩斯密碼發送應用程序。現在,讓我們繼續探索更多令人興奮的功能和可能性,為我們的專案劃上美好的句點!/images/emoticon/emoticon02.gif

UI畫面

https://ithelp.ithome.com.tw/upload/images/20230819/201503698CmIoeQNt9.png

程式碼

這個方法處理了當用戶點擊"post"按鈕時的操作。根據條件,它可能啟動摩斯密碼的發送(使用光線或蜂鳴器),隱藏軟鍵盤,或者停止正在進行的發送操作。如果輸入框為空,它會顯示一條提示消息。

/** 
 * 當"post"按鈕被點擊時觸發的方法。
 */
private void postBtClicked(View view) {
    // 檢查"刪除"按鈕是否啟用(在某些情況下需要停止操作)
    if (delete_button.isEnabled()) {
        // 檢查輸入框是否不為空
        if (!TextUtils.isEmpty(input_editText.getText())) {
            // 隱藏軟鍵盤
            InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(input_editText.getWindowToken(), 0);
            
            // 清除輸入框的焦點
            input_editText.clearFocus();
            
            // 根據"是否改變"標誌啟動對應的摩斯密碼發送方式
            if (isChange) {
                morsePostPresenter.startLighting(String.valueOf(input_editText.getText()));
            } else {
                morsePostPresenter.startBee(String.valueOf(input_editText.getText()));
            }
            
            // 清空輸入框的內容
            input_editText.setText("");
        } else {
            showToast("請先輸入要發送的密碼!");
        }
    } else {
        // 停止摩斯密碼發送線程
        morsePostPresenter.stopPostThread();
    }

一樣的我們的發送也是寫在 Presenter , 我們先寫好開關手電筒,讓之後要做摩斯密碼打燈時或發出 Bee 聲,只要叫這個 funtion 就好。

private void openLight() {
    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // 使用相機管理器打開閃光燈
            cameraManager.setTorchMode(cameraId, true);
        }
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

/**
 * 關閉手機的閃光燈(照明模式)。
 * 請注意,這個方法僅在Android 6.0(API級別23)及以上版本有效。
 */
private void closeLight() {
    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // 使用相機管理器關閉閃光燈
            cameraManager.setTorchMode(cameraId, false);
        }
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

/**
 * 播放蜂鳴聲音效。
 */
private void playBee() {
    if (mediaPlayer == null) {
        // 創建 MediaPlayer 對象,並設置為循環播放蜂鳴聲音效
        mediaPlayer = MediaPlayer.create(activity, R.raw.beep);
        mediaPlayer.setLooping(true);
    }
    mediaPlayer.start(); // 開始播放聲音
}

/**
 * 停止蜂鳴聲音效的播放。
 */
private void stopBee() {
    if (mediaPlayer != null) {
        mediaPlayer.stop(); // 停止播放聲音
        mediaPlayer.release(); // 釋放 MediaPlayer 資源
        mediaPlayer = null;
    }
}

這些方法用於控制莫斯密碼的發送。startLighting 方法開始使用閃光燈模式發送莫斯密碼,並創建一個對應的線程來執行發送操作。startBee 方法開始使用蜂鳴器模式發送莫斯密碼,同樣創建一個對應的線程。stopPostThread 方法用於停止正在運行的莫斯密碼發送線程,不論是閃光燈模式還是蜂鳴器模式,並釋放相關資源。

/**
 * 開始使用閃光燈模式發送莫斯密碼。
 * @param inputCode 要發送的莫斯密碼字符串
 */
@Override
public void startLighting(String inputCode) {
    // 創建並啟動閃光燈模式的線程
    getLightThread = getLightThread(inputCode);
    getLightThread.start();
}

/**
 * 開始使用蜂鳴器模式發送莫斯密碼。
 * @param inputCode 要發送的莫斯密碼字符串
 */
@Override
public void startBee(String inputCode) {
    // 創建並啟動蜂鳴器模式的線程
    getBeeThread = getBeeThread(inputCode);
    getBeeThread.start();
}

/**
 * 停止正在運行的莫斯密碼發送線程(不論是閃光燈模式還是蜂鳴器模式)。
 */
@Override
public void stopPostThread() {
    // 如果閃光燈模式的線程存在,則停止並釋放相關資源
    if (getLightThread != null) {
        synchronized (getLightThread) {
            getLightThread.interrupt();
            view.lockComponent(true);
            view.setNowPostCodeText("");
        }
    }
    // 如果蜂鳴器模式的線程存在,則停止並釋放相關資源
    if (getBeeThread != null) {
        synchronized (getBeeThread) {
            getBeeThread.interrupt();
            view.lockComponent(true);
            view.setNowPostCodeText("");
        }
    }
}

最後就是發送的方法拉,這邊就只介紹用手電筒發送的方法因為兩個都大同小異,。在循環中,它逐字符處理要發送的密碼,打開閃光燈以表示不同的莫斯密碼("." 和 "-"),然後等待一段時間以實現燈光的長度。方法中還處理了中斷請求,以便在停止發送時能夠中斷線程。最後,它在發送完成後回到 UI 線程,設置相關的 UI 元素狀態。

/**
 * 創建一個用於閃光燈模式的發送莫斯密碼的線程。
 * @param inputCode 要發送的莫斯密碼字符串
 * @return 表示閃光燈模式莫斯密碼發送的線程
 */
private Thread getLightThread(String inputCode) {
    return new Thread(() -> {
        // 在 UI 線程上設置發送按鈕文本,解鎖 UI 元素
        activity.runOnUiThread(() -> {
            view.setPostButtonText(R.string.stop);
            view.lockComponent(false);
        });

        // 逐字符處理要發送的莫斯密碼
        for (String code : inputCode.split("")) {
            if (morseCodeTool.get(code.toLowerCase()) == null) {
                continue; // 如果字符不在莫斯密碼表中,則跳過
            }
            if (Thread.currentThread().isInterrupted()) { // 檢查是否有中斷請求
                break;
            }
            // 在 UI 線程上設置當前正在發送的字符
            activity.runOnUiThread(() -> {
                view.setNowPostCodeText(code);
            });

            if (!code.equals(" ") && !code.equals("\n")) {
                for (String i : morseCodeTool.get(code.toLowerCase()).split("")) {
                    if (Thread.currentThread().isInterrupted()) { // 檢查是否有中斷請求
                        break;
                    }

                    openLight(); // 開啟閃光燈

                    if (i.equals(".")) {
                        try {
                            Thread.sleep(5000 / postSpeed); // 燈亮的時間,正常速度為 1 單位
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            e.printStackTrace();
                        }
                    } else {
                        try {
                            Thread.sleep(10000 / postSpeed); // 燈亮的時間,正常速度為 3 單位
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            e.printStackTrace();
                        }
                    }

                    closeLight(); // 關閉閃光燈
                    try {
                        Thread.sleep(6000 / postSpeed); // 燈暗的時間,正常速度為 1 單位
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        e.printStackTrace();
                    }
                }
            }

            try {
                Thread.sleep(12000 / postSpeed); // 單個字符之間的間隔,正常速度為 3 倍單位
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                e.printStackTrace();
            }
        }

        // 在發送完成後,恢復 UI 狀態,清除正在發送的字符
        activity.runOnUiThread(() -> {
            view.setPostButtonText(R.string.post);
            view.lockComponent(true);
            view.setNowPostCodeText("");
        });
    });
}

終於把我們的小專案講解完了,接下來可能會在介紹一些 Android 的東西,才會來到我們的 Spring boot~~~~!!
/images/emoticon/emoticon01.gif


上一篇
[Android Studio & Spring boot 30天挑戰] Day11- 摩斯密碼發送(中)
下一篇
[Android Studio & Spring boot 30天挑戰] Day13- Lottie 動畫
系列文
[Android Studio & Spring boot 30天挑戰]30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言